/***************************************************************************************
 * Copyright 2020 Infineon Technologies AG ( www.infineon.com ).                       *
 * All rights reserved.                                                                *
 *                                                                                     *
 * Licensed  Material-Property of Infineon Technologies AG.                            *
 * This software is made available solely pursuant to the terms of Infineon            *
 * Technologies AG agreement which governs its use. This code and the information      *
 * contained in it are proprietary and confidential to Infineon Technologies AG.       *
 * No person is allowed to copy, reprint, reproduce or publish any part of this code,  *
 * nor disclose its contents to others, nor make any use of it, nor allow or assist    *
 * others to make any use of it - unless by prior Written express authorization of     *
 * Infineon Technologies AG and then only to the extent authorized.                    *
 *                                                                                     *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,            *
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,           *
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO       *
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,                 *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;         *
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY             *
 * WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR            *
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF              *
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                          *
 *                                                                                     *
 ***************************************************************************************/
/**
 * @file   usecase.c
 * @date   June, 2020
 * @brief  Implementation of use case
 */
#include <stdio.h>

#include "auths_api.h"
#include "auths_config.h"
#include "auths_status.h"
#include "host_auth.h"
#include "i2c_bus_command.h"
#include "nvm.h"
#include "helper.h"

extern AuthS_Capability auths_capability;
uint8_t g_DevAddr=AUTHS_DEFAULT_ADDRESS;

//IMPORTANT: THIS IS A DESTRUCTIVE TEST CASE. ONCE THE ECC IS KILLED, IT IS NOT REVERSIBLE.
void test_kill_ecc_auto()
{
	//uint8_t input[1]={0};
	uint16_t ret;
	uint8_t ub_data;
	uint32_t lsc;
	uint8_t ub_rddata[UID_BYTE_LEN];
	uint16_t count=2048;
	
	do{

		if(auths_get_ifx_config(AUTOKILL_CONFIG)== APP_ECC_DISABLE_AUTOKILL){
			PRINT("Error: Auto kill is disabled\r\n");
			return;
		}

		if(auths_get_ifx_config(KILL_CONFIG)== APP_ECC_DISABLE_KILL){
			PRINT("Error: Kill is disabled\r\n");
			return;
		}
		PRINT("Kill ECC when LSC1 decrease to 0 is enabled\r\n\r\n");
		
		// Check auto kill config set
		ret = Intf_ReadRegister(AUTHS_SFR_LOCK_STS, &ub_data, 1);
		if(SDK_INTERFACE_SUCCESS != ret){
			PRINT("Error: Read AUTHS_SFR_LOCK_STS failed, ret=0x%x\r\n", ret);
			return;
		}

		if(((ub_data >> BIT_IFX_AUTO_KILL_CONF) & 0x01) != 0x01){
			PRINT("Error: IFX_AUTO_KILL_CONF is not set!!\r\n");
			return;
		}

		// check kill bit was set or not
		ret = Intf_ReadRegister(AUTHS_SFR_LSC_KILL_ACT_STS_1, &ub_data,1);
		if(SDK_INTERFACE_SUCCESS != ret){
			PRINT("Read AUTHS_SFR_LSC_KILL_ACT_STS_1 failed, ret=0x%x\r\n", ret);
			break;
		}
		if(((ub_data >> BIT_KILL_IND) & 0x01) == 0x01){
			PRINT("Error: BIT_KILL_IND is already set\r\n");
			return;
		}

		// set all LSC_EN
		PRINT("Set all LSC_EN in AUTHS_SFR_LSC_KILL_CONF_1\r\n");
		ub_data = (1<<BIT_LSC_1_EN)|(1<<BIT_LSC_2_EN)|(1<<BIT_LSC_3_EN)|(1<<BIT_LSC_4_EN);
		ret = Intf_WriteRegister(AUTHS_SFR_LSC_KILL_CONF_1, &ub_data, 1);
		if(SDK_INTERFACE_SUCCESS != ret){
			PRINT("Error: Write AUTHS_SFR_LSC_KILL_CONF_1 failed, ret=0x%x\r\n", ret);
			return;
		}
		delay_ms(7);

		PRINT("Decrease LSC1 to 0\r\n");
				
		ret = auths_set_lsc_decvalue(0, count);
		if(APP_LSC_SUCCESS != ret){
			PRINT("Error: Decrease LSC%d failed, ret=0x%x\r\n", ret);
			return;
		}
				
		ret = auths_get_lsc_value(0, &lsc);
		if(APP_LSC_SUCCESS != ret){
			PRINT("Error: Read LSC1 failed, ret=0x%x\r\n", ret);
			return;
		}else{
			PRINT("LSC1 = 0x%.8X\r\n", lsc);
		}
				
	}while(lsc > 0);

	// run one ECC to trigger KIll, expect fail
	ret = Intf_ReadRegister(AUTHS_UID_ADDR, ub_rddata, UID_BYTE_LEN);
	if(AUTHS_SUCCESS != ret){
		PRINT("Error: Read UID failed, ret=0x%x\r\n", ret);
	}
	PRINT("Run ECC\r\n");
	auths_exe_ecc(0, MAC_GROUP_0);

	delay_ms(20);

#if (CONFIG_HOSTAUTH == 1)
	ret = auths_exe_host_authentication();
	if (APP_HA_SUCCESS != ret) {
		PRINT_C(RED, "Host Authentication failed, ret=0x%x\r\n", ret);
		//return;
	} else {
		PRINT("Host Authenticated\r\n");
	}
#endif
	// check kill bit was set
	ret = Intf_ReadRegister(AUTHS_SFR_LSC_KILL_ACT_STS_1, &ub_data, 1);
	if(AUTHS_SUCCESS != ret){
		PRINT("Read AUTHS_SFR_LSC_KILL_ACT_STS_1 failed, ret=0x%x", ret);
	}
	if(((ub_data >> BIT_KILL_IND) & 0x01) != 0x01){
		PRINT("BIT_KILL_IND is not set\r\n");
		return;
	}
	PRINT("Kill ECC succeed.\r\n");
    
}

uint16_t SFR_Read(uint16_t sfr_address, uint8_t *sfr_value)
{
	uint16_t ret;

	ret = Intf_ReadRegister(sfr_address, sfr_value, 1);
	if (SDK_INTERFACE_SUCCESS!=ret ){
		PRINT_C(RED, "Read Register 0x%.4X failed. ret=%x\r\n", sfr_address, ret);
		return ret;
	}
	delay_ms(1);
	PRINT("0x%.4X = 0x%.2X\r\n", sfr_address, *sfr_value);
	return ret;

}

void nvm_lock_status(void)
{
	uint16_t ret;	
	uint8_t j,k;
	uint16_t uwRegAddr;
	uint8_t ubRdData;
	
	uwRegAddr = AUTHS_SFR_USER_NVM_LOCK_STS_1;

#if (CONFIG_NVM_SIZE == 1)
		for(j = 0; j < 1;j ++)
		{
#elif (CONFIG_NVM_SIZE == 2)
		for(j = 0; j < 2;j ++)
		{
#elif (CONFIG_NVM_SIZE == 5)
		for(j = 0; j < 6;j ++)
		{
#endif
		ret = SFR_Read(uwRegAddr, &ubRdData);
		if (SDK_INTERFACE_SUCCESS == ret) {
			PRINT("NVM User Page Lock status(0x%X): 0x%.2X\r\n", uwRegAddr, ubRdData);
		}

		if (ubRdData != 0) {
			PRINT("Locked pages: ");
			for (k = 0; k < 8; k++) {
				if (((ubRdData >> k) & 0x01) == 0x01) {
					ret = (j << 5) + k * 4;
					PRINT("%d to %d, ", ret, ret + 3);
					}
			}
			PRINT("\r\n");
		}
			uwRegAddr++;
		}

		ret = SFR_Read(AUTHS_SFR_LSC_KILL_FEAT_STS_1, &ubRdData);
		if (SDK_INTERFACE_SUCCESS != ret) {
			PRINT("Error: Read LSC Kill Feat Stat 1, ret=0x%x\r\n", ret);
		}
		PRINT("LSC_KILL_FEAT_STATUS_1: 0x%.2X\r\n", ubRdData);

		ret = SFR_Read(AUTHS_SFR_LSC_KILL_FEAT_STS_2, &ubRdData);
		if (SDK_INTERFACE_SUCCESS != ret) {
			PRINT("Error: Read LSC Kill Feat Stat 2, ret=0x%x\r\n", ret);
		}
		//PRINT("LSC_KILL_FEAT_STATUS_2: 0x%.2X\r\n", ubRdData);

		ret = SFR_Read(AUTHS_SFR_LSC_KILL_ACT_STS_1, &ubRdData);
		if (SDK_INTERFACE_SUCCESS != ret) {
			PRINT("Error: Read LSC Kill Act Stat 1, ret=0x%x\r\n", ret);
		}
		//PRINT("LSC_KILL_ACT_STATUS_1: 0x%.2X\r\n", ubRdData);

		ret = SFR_Read(AUTHS_SFR_LSC_KILL_ACT_STS_2, &ubRdData);
		if (SDK_INTERFACE_SUCCESS != ret) {
			PRINT("Error: Read LSC Kill Act Stat 2, ret=0x%x\r\n", ret);
		}
		//PRINT("LSC_KILL_ACT_STATUS_2: 0x%.2X\r\n", ubRdData);

		ret = SFR_Read(AUTHS_SFR_LOCK_STS, &ubRdData);
		if (SDK_INTERFACE_SUCCESS != ret) {
			PRINT("Error: Read LSC Kill Act Stat 2, ret=0x%x\r\n", ret);
		}
		//PRINT("RegAddr_LOCK_STS: 0x%.2X\r\n", ubRdData);

		ret = SFR_Read(AUTHS_SFR_LSC_DEC_VAL_H, &ubRdData);
		if (SDK_INTERFACE_SUCCESS != ret) {
			PRINT("Error: Read LSC DEC VAL H, ret=0x%x\r\n", ret);
		}
		//PRINT("RegAddr_LSC_DEC_VAL_H: 0x%.2X\r\n", ubRdData);

		ret = SFR_Read(AUTHS_SFR_LSC_DEC_VAL_L	, &ubRdData);
		if (SDK_INTERFACE_SUCCESS != ret) {
			PRINT("Error: Read LSC DEC VAL L, ret=0x%x\r\n", ret);			
		}
		//PRINT("RegAddr_LSC_DEC_VAL_L: 0x%.2X\r\n", ubRdData);

	return;
}

void read_all_sfr(void){
	uint8_t uwDevAddr[50] = {0x0};
	uint8_t* uwDevAddr_ptr=uwDevAddr;

	PRINT("Info: SFR Dump\r\n");

	//SFR_Read(AUTHS_SFR_USER_NVM_LOCK_1, uwDevAddr_ptr);   //Write-Only SFR
	//SFR_Read(AUTHS_SFR_USER_NVM_LOCK_2, uwDevAddr_ptr++); //Write-Only SFR
	//SFR_Read(AUTHS_SFR_USER_NVM_LOCK_3, uwDevAddr_ptr++); //Write-Only SFR
	//SFR_Read(AUTHS_SFR_USER_NVM_LOCK_4, uwDevAddr_ptr++); //Write-Only SFR
	//SFR_Read(AUTHS_SFR_USER_NVM_LOCK_5, uwDevAddr_ptr++); //Write-Only SFR
	//SFR_Read(AUTHS_SFR_USER_NVM_LOCK_6, uwDevAddr_ptr++); //Write-Only SFR

	SFR_Read(AUTHS_SFR_USER_NVM_LOCK_STS_1, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_USER_NVM_LOCK_STS_2, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_USER_NVM_LOCK_STS_3, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_USER_NVM_LOCK_STS_4, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_USER_NVM_LOCK_STS_5, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_USER_NVM_LOCK_STS_6, uwDevAddr_ptr++);

	//SFR_Read(AUTHS_SFR_LSC_KILL_CTRL, uwDevAddr_ptr++); //Write-Only SFR
	//SFR_Read(AUTHS_SFR_LSC_KILL_CONF_1, uwDevAddr_ptr++); //Write-Only SFR
	//SFR_Read(AUTHS_SFR_LSC_KILL_CONF_2, uwDevAddr_ptr++); //Write-Only SFR

	SFR_Read(AUTHS_SFR_LSC_KILL_FEAT_STS_1, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_LSC_KILL_FEAT_STS_2, uwDevAddr_ptr++);

	SFR_Read(AUTHS_SFR_LSC_KILL_ACT_STS_1, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_LSC_KILL_ACT_STS_2, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_BUSY_STS, uwDevAddr_ptr++);

	SFR_Read(AUTHS_SFR_DEVICE_ADDR, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_LOCK_STS, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_LSC_DEC_VAL_L	, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_LSC_DEC_VAL_H, uwDevAddr_ptr++);

	SFR_Read(AUTHS_SFR_SWI_CONF_0, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_SWI_CONF_1, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_SWI_STS_0, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_SWI_STS_1, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_SWI_STS_2, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_SWI_INT_0, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_SWI_INT_1, uwDevAddr_ptr++);

	SFR_Read(AUTHS_SFR_SWI_DADR0_L, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_SWI_DADR0_H, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_SWI_RD_LEN, uwDevAddr_ptr++);
	SFR_Read(AUTHS_SFR_SWI_WD_LEN, uwDevAddr_ptr++);
	//SFR_Read(AUTHS_SFR_GPO_CTRL, uwDevAddr_ptr++);  //Write-Only SFR
	SFR_Read(AUTHS_SFR_GPO_CTRL_STS, uwDevAddr_ptr++);
}
